package user

import (
	"context"
	// "fmt"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/utils/pointy"
	"mall/service/backend/model"
	"mall/service/backend/rpc/internal/svc"
	"mall/service/backend/rpc/internal/utils/errorhandler"
	"mall/service/backend/rpc/types/backend"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetUserListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
	return &GetUserListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetUserListLogic) GetUserList(in *backend.UserListReq) (*backend.UserListResp, error) {
	// logrus.Info(fmt.Sprintf("UserListReq: %+v", in))

	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			if orderBy.Field == "id" {
				orderBys = append(orderBys, model.SysUserColumns.ID+order)
			}
			if orderBy.Field == "createdAt" {
				orderBys = append(orderBys, model.SysUserColumns.CreatedAt+order)
			}
		}
	}

	var stati string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			if filterBy.Field == "status" {
				stati = filterBy.In
			}
		}
	}

	var ids []any
	var page uint64
	var pageSize uint64
	filterMap := make(map[string]map[string][]any)
	if in.Ids != nil {
		ids = modelx.UniqueInterfaces(*in.Ids, 64)
	}

	statusIn := modelx.UniqueInterfaces(stati, 32)
	statusMap := make(map[string][]any)
	if len(statusIn) > 0 {
		statusMap["in"] = statusIn
	}
	if in.Status != nil {
		statusMap["equalTo"] = []any{*in.Status}
	}
	filterMap[model.SysUserColumns.Status] = statusMap

	if in.Username != nil {
		filterMap[model.SysUserColumns.Username] = map[string][]any{
			"contain": []any{*in.Username},
		}
	}
	if in.Nickname != nil {
		filterMap[model.SysUserColumns.Nickname] = map[string][]any{
			"contain": []any{*in.Nickname},
		}
	}
	if in.Email != nil {
		filterMap[model.SysUserColumns.Email] = map[string][]any{
			"equalTo": []any{*in.Email},
		}
	}
	if in.Mobile != nil {
		filterMap[model.SysUserColumns.Mobile] = map[string][]any{
			"equalTo": []any{*in.Mobile},
		}
	}
	if in.DepartmentId != nil {
		filterMap[model.SysUserColumns.DepartmentID] = map[string][]any{
			"equalTo": []any{*in.DepartmentId},
		}
	}
	var startTimeIn []any
	var endTimeIn []any
	if in.StartTime != nil && len(strings.TrimSpace(*in.StartTime)) > 0 {
		if startTime, err := modelx.ParseLocalDate(strings.TrimSpace(*in.StartTime)); err == nil {
			startTimeIn = append(startTimeIn, startTime)
		}
	}
	if in.EndTime != nil && len(strings.TrimSpace(*in.EndTime)) > 0 {
		if endTime, err := modelx.ParseLocalDate(strings.TrimSpace(*in.EndTime)); err == nil {
			endTimeIn = append(endTimeIn, endTime)
		}
	}
	createdAtMap := make(map[string][]any)
	if len(startTimeIn) > 0 {
		createdAtMap["moreThan"] = startTimeIn
	}
	if len(endTimeIn) > 0 {
		createdAtMap["lessThanOrEqualTo"] = endTimeIn
	}
	filterMap[model.SysUserColumns.CreatedAt] = createdAtMap

	if in.RoleIds != nil {
		if len(in.RoleIds) > 0 {
			var rids []any
			for _, rid := range in.RoleIds {
				rids = append(rids, rid)
			}
			preFilterMap := make(map[string]map[string][]any)
			preFilterMap[model.SysUserRoleRelationshipColumns.RoleID] = map[string][]any{
				"in": rids,
			}
			if len(ids) > 0 {
				preFilterMap[model.SysUserRoleRelationshipColumns.UserID] = map[string][]any{
					"in": ids,
				}
			}
			rel, _, err := l.svcCtx.SysUser.GetRelRoleList(l.ctx, model.M{}, -1, preFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(rel) > 0 {
				var uids []any
				for _, v := range rel {
					uids = append(uids, v.UserID)
				}
				ids = uids[:]
			}
		}
	}
	if in.PositionIds != nil {
		if len(in.PositionIds) > 0 {
			var pids []any
			for _, pid := range in.PositionIds {
				pids = append(pids, pid)
			}
			preFilterMap := make(map[string]map[string][]any)
			preFilterMap[model.SysUserPositionRelationshipColumns.RelationshipID] = map[string][]any{
				"in": pids,
			}
			if len(ids) > 0 {
				preFilterMap[model.SysUserPositionRelationshipColumns.UserID] = map[string][]any{
					"in": ids,
				}
			}
			rel, _, err := l.svcCtx.SysUser.GetRelPositionList(l.ctx, model.M{}, -1, preFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(rel) > 0 {
				var uids []any
				for _, v := range rel {
					uids = append(uids, v.UserID)
				}
				ids = uids[:]
			}
		}
	}

	if len(ids) > 0 {
		filterMap[model.SysUserColumns.ID] = map[string][]any{
			"in": ids,
		}
	} else {
		page = in.Page
		pageSize = in.PageSize
	}

	// logrus.Info(fmt.Sprintf("filterMap: %+v", filterMap))

	users, count, err := l.svcCtx.SysUser.GetList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  strings.Join(orderBys, ","),
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp := &backend.UserListResp{
		Total: uint64(count),
	}

	if len(users) > 0 {
		var uids []any
		for _, v := range users {
			uids = append(uids, v.ID)
		}

		idRoleMap := make(map[uint64][]*backend.RoleInfo)
		if in.WithRoles != nil && *in.WithRoles > 0 {
			preFilterMap := make(map[string]map[string][]any)
			preFilterMap[model.SysUserRoleRelationshipColumns.UserID] = map[string][]any{
				"in": uids,
			}
			rel, _, err := l.svcCtx.SysUser.GetRelRoleList(l.ctx, model.M{}, -1, preFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(rel) > 0 {
				ridMap := make(map[uint64][]uint64)
				var rids []any
				for _, v := range rel {
					rids = append(rids, v.RoleID)
					ridMap[v.RoleID] = append(ridMap[v.RoleID], v.UserID)
				}

				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.SysRoleColumns.ID] = map[string][]any{
					"in": rids,
				}
				subFilterMap[model.SysRoleColumns.Status] = map[string][]any{
					"equalTo": []any{globalkey.StatusEnabled},
				}
				roles, _, err := l.svcCtx.SysRole.GetList(l.ctx, model.M{
					"select": model.SysRoleColumns.ID + "," + model.SysRoleColumns.Code,
				}, -1, subFilterMap)
				if err != nil {
					return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
				}

				if len(roles) > 0 {
					for _, v := range roles {
						if ruids, ok := ridMap[v.ID]; ok {
							ruidMap := make(map[uint64]struct{})
							for _, ruid := range ruids {
								if _, exist := ruidMap[ruid]; !exist {
									idRoleMap[ruid] = append(idRoleMap[ruid], &backend.RoleInfo{
										Id:   &v.ID,
										Code: &v.Code,
									})
									ruidMap[ruid] = struct{}{}
								}
							}
						}
					}
				}
			}
		}

		idPositionMap := make(map[uint64][]uint64)
		if in.WithPositions != nil && *in.WithPositions > 0 {
			preFilterMap := make(map[string]map[string][]any)
			preFilterMap[model.SysUserPositionRelationshipColumns.UserID] = map[string][]any{
				"in": uids,
			}
			rel, _, err := l.svcCtx.SysUser.GetRelPositionList(l.ctx, model.M{}, -1, preFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(rel) > 0 {
				pidMap := make(map[uint64][]uint64)
				var pids []any
				for _, v := range rel {
					pids = append(pids, v.PositionID)
					pidMap[v.PositionID] = append(pidMap[v.PositionID], v.UserID)
				}

				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.SysPositionColumns.ID] = map[string][]any{
					"in": pids,
				}
				subFilterMap[model.SysPositionColumns.Status] = map[string][]any{
					"equalTo": []any{globalkey.StatusEnabled},
				}
				positions, _, err := l.svcCtx.SysPosition.GetList(l.ctx, model.M{
					"select": ",",
				}, -1, subFilterMap)
				if err != nil {
					return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
				}

				if len(positions) > 0 {
					for _, v := range positions {
						if puids, ok := pidMap[v.ID]; ok {
							puidMap := make(map[uint64]bool)
							for _, puid := range puids {
								if _, exist := puidMap[puid]; !exist {
									idPositionMap[puid] = append(idPositionMap[puid], v.ID)
									puidMap[puid] = true
								}
							}
						}
					}
				}
			}
		}

		for _, v := range users {
			var roleIds []uint64
			var roleCodes []string
			if roles, ok := idRoleMap[v.ID]; ok {
				if len(roles) > 0 {
					for _, role := range roles {
						roleIds = append(roleIds, *role.Id)
						roleCodes = append(roleCodes, *role.Code)
					}
				}
			}
			var positionIds []uint64
			if pids, ok := idPositionMap[v.ID]; ok {
				positionIds = pids[:]
			}
			resp.List = append(resp.List, &backend.UserInfo{
				Id:            pointy.GetPointer(v.ID),
				Username:      pointy.GetPointer(v.Username),
				Nickname:      pointy.GetPointer(v.Nickname),
				RoleIds:       roleIds,
				RoleCodes:     roleCodes,
				Status:        pointy.GetPointer(uint32(v.Status)),
				Email:         pointy.GetPointer(v.Email),
				Mobile:        pointy.GetPointer(v.Mobile),
				DepartmentId:  pointy.GetPointer(v.DepartmentID),
				PositionIds:   positionIds,
				Avatar:        pointy.GetPointer(v.Avatar),
				Description:   pointy.GetPointer(v.Description),
				HomePath:      pointy.GetPointer(v.HomePath),
				CreatedAt:     pointy.GetPointer(modelx.FormatTime(v.CreatedAt, "")),
				UpdatedAt:     pointy.GetPointer(modelx.FormatTime(v.UpdatedAt, "")),
				DeletedAt:     pointy.GetPointer(modelx.FormatNullDotTime(v.DeletedAt, "")),
				LastLoginTime: pointy.GetPointer(modelx.FormatNullDotTime(v.LastLoginTime, "")),
			})
		}
	}

	return resp, nil
}
